package com.piece.core.framework.util.net;

import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.string.StringUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.net.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

@Data
@AllArgsConstructor
public class URLBuilder {
    private String scheme;
    private String host;
    private int port = -1;
    private URLPath path;
    private URLQuery query;
    private String fragment;
    private Charset charset;

    public URLBuilder() {
        this.charset = StandardCharsets.UTF_8;
    }

    public String build() {
        return this.toURL().toString();
    }

    public static URLBuilder of(URI uri, Charset charset) {
        return of(uri.getScheme(), uri.getHost(), uri.getPort(), uri.getPath(), uri.getRawQuery(), uri.getFragment(), charset);
    }

    public static URLBuilder of(String url, Charset charset) {
        return of(URLUtil.url(url.trim()), charset);
    }

    public static URLBuilder of(URL url, Charset charset) {
        return of(url.getProtocol(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef(), charset);
    }

    public static URLBuilder of(String scheme, String host, int port, String path, String query, String fragment, Charset charset) {
        return of(scheme, host, port, URLPath.of(path, charset), URLQuery.of(query, charset, false), fragment, charset);
    }

    public static URLBuilder of(String scheme, String host, int port, URLPath path, URLQuery query, String fragment, Charset charset) {
        return new URLBuilder(scheme, host, port, path, query, fragment, charset);
    }

    public static URLBuilder ofHttp(String httpUrl, Charset charset) {
        int sepIndex = httpUrl.indexOf("://");
        if (sepIndex < 0) {
            httpUrl = "http://" + httpUrl.trim();
        }

        return of(httpUrl, charset);
    }

    public static URLBuilder ofHttpWithoutEncode(String httpUrl) {
        return ofHttp(httpUrl, null);
    }

    public String getSchemeWithDefault() {
        return Convert.toStr(this.scheme, "http");
    }

    public String getAuthority() {
        return this.port < 0 ? this.host : this.host + ":" + this.port;
    }

    public String getPathStr() {
        return null == this.path ? "/" : this.path.build(this.charset);
    }

    public URLBuilder addPath(String segment) {
        if (!StringUtil.isBlank(segment)) {
            if (null == this.path) {
                this.path = new URLPath();
            }

            this.path.add(segment);
        }
        return this;
    }

    public URLBuilder appendPath(CharSequence segment) {
        if (!StringUtil.isEmpty(segment)) {
            if (null == this.path) {
                this.path = new URLPath();
            }

            this.path.add(segment);
        }
        return this;
    }

    public String getQueryStr() {
        return null == this.query ? null : this.query.build(this.charset);
    }

    public URLBuilder addQuery(String key, String value) {
        if (!StringUtil.isEmpty(key)) {
            if (null == this.query) {
                this.query = new URLQuery();
            }

            this.query.add(key, value);
        }
        return this;
    }

    public String getFragmentEncoded() {
        return URLEncoder.ALL.encode(this.fragment, this.charset);
    }

    public URLBuilder setFragment(String fragment) {
        if (StringUtil.isEmpty(fragment)) {
            this.fragment = null;
        }

        this.fragment = StringUtil.removeStart(fragment, "#");
        return this;
    }

    public URL toURL() {
        return this.toURL(null);
    }

    public URL toURL(URLStreamHandler handler) {
        StringBuilder fileBuilder = new StringBuilder();
        fileBuilder.append(Convert.toStr(this.getPathStr(), "/"));
        String query = this.getQueryStr();
        if (StringUtil.isNotBlank(query)) {
            fileBuilder.append('?').append(query);
        }

        if (StringUtil.isNotBlank(this.fragment)) {
            fileBuilder.append('#').append(this.getFragmentEncoded());
        }

        try {
            return new URL(this.getSchemeWithDefault(), this.host, this.port, fileBuilder.toString(), handler);
        } catch (MalformedURLException var5) {
            return null;
        }
    }

    public URI toURI() {
        try {
            return new URI(this.getSchemeWithDefault(), this.getAuthority(), this.getPathStr(), this.getQueryStr(), this.getFragmentEncoded());
        } catch (URISyntaxException var2) {
            return null;
        }
    }

    public String toString() {
        return this.build();
    }
}